using System;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Pool;

/// <summary>
/// 网络对象池，用于通过Netcode复用网络对象。
/// 默认情况下，Netcode在生成新对象时会分配新内存。使用此对象池可重用对象。
/// 注意：Boss Room示例中用于弹幕，理论上也可用于其他高频生成对象（如小怪）。
/// 通过挂钩NetworkManager的PrefabHandler实现自定义生成逻辑。
/// </summary>
public class NetworkObjectPool : NetworkBehaviour
{
    // 单例实例
    public static NetworkObjectPool Singleton { get; private set; }

    [SerializeField]
    List<PoolConfigObject> PooledPrefabsList; // 配置列表：需池化的预制体及其预热数量

    HashSet<GameObject> m_Prefabs = new HashSet<GameObject>(); // 已注册的预制体集合
    Dictionary<GameObject, ObjectPool<NetworkObject>> m_PooledObjects = new Dictionary<GameObject, ObjectPool<NetworkObject>>(); // 预制体-对象池映射

    /// <summary>
    /// 单例初始化，防止重复实例
    /// </summary>
    public void Awake()
    {
        if (Singleton != null && Singleton != this)
        {
            Destroy(gameObject);
        }
        else
        {
            Singleton = this;
        }
    }

    /// <summary>
    /// 网络对象生成时调用：注册所有配置的预制体到对象池
    /// </summary>
    public override void OnNetworkSpawn()
    {
        foreach (var configObject in PooledPrefabsList)
        {
            RegisterPrefabInternal(configObject.Prefab, configObject.PrewarmCount);
        }
    }

    /// <summary>
    /// 网络对象销毁时调用：清理所有池对象和处理器
    /// </summary>
    public override void OnNetworkDespawn()
    {
        foreach (var prefab in m_Prefabs)
        {
            NetworkManager.Singleton.PrefabHandler.RemoveHandler(prefab);
            m_PooledObjects[prefab].Clear();
        }
        m_PooledObjects.Clear();
        m_Prefabs.Clear();
    }

    /// <summary>
    /// 编辑器验证：确保所有预制体包含NetworkObject组件
    /// </summary>
    public void OnValidate()
    {
        for (var i = 0; i < PooledPrefabsList.Count; i++)
        {
            var prefab = PooledPrefabsList[i].Prefab;
            if (prefab != null)
            {
                Assert.IsNotNull(
                    prefab.GetComponent<NetworkObject>(), 
                    $"{nameof(NetworkObjectPool)}: 预制体 '{prefab.name}' 缺少 {nameof(NetworkObject)} 组件（索引 {i}）"
                );
            }
        }
    }

    /// <summary>
    /// 从池中获取网络对象（需在服务端调用）
    /// </summary>
    /// <param name="prefab">目标预制体</param>
    /// <param name="position">生成位置</param>
    /// <param name="rotation">生成旋转</param>
    /// <returns>激活的NetworkObject实例</returns>
    public NetworkObject GetNetworkObject(GameObject prefab, Vector3 position, Quaternion rotation)
    {
        var networkObject = m_PooledObjects[prefab].Get(); // 从池中取出对象
        networkObject.transform.SetPositionAndRotation(position, rotation); // 设置位置和旋转
        return networkObject;
    }

    /// <summary>
    /// 将网络对象返回池中（服务端/客户端同步调用）
    /// </summary>
    /// <param name="networkObject">要回收的对象</param>
    /// <param name="prefab">对应的预制体</param>
    public void ReturnNetworkObject(NetworkObject networkObject, GameObject prefab)
    {
        m_PooledObjects[prefab].Release(networkObject); // 放回池中
    }

    /// <summary>
    /// 内部方法：为预制体创建对象池并预热
    /// </summary>
    /// <param name="prefab">目标预制体</param>
    /// <param name="prewarmCount">预热数量</param>
    private void RegisterPrefabInternal(GameObject prefab, int prewarmCount)
    {
        // 定义对象池的四个核心行为
        NetworkObject CreateFunc()
        {
            return Instantiate(prefab).GetComponent<NetworkObject>(); // 创建新实例
        }

        void ActionOnGet(NetworkObject networkObject)
        {
            networkObject.gameObject.SetActive(true); // 取出时激活对象
        }

        void ActionOnRelease(NetworkObject networkObject)
        {
            networkObject.gameObject.SetActive(false); // 放回时禁用对象
        }

        void ActionOnDestroy(NetworkObject networkObject)
        {
            Destroy(networkObject.gameObject); // 销毁对象（当池被清理时）
        }

        m_Prefabs.Add(prefab); // 记录已注册的预制体

        // 创建对象池并设置容量
        m_PooledObjects[prefab] = new ObjectPool<NetworkObject>(
            CreateFunc, 
            ActionOnGet, 
            ActionOnRelease, 
            ActionOnDestroy, 
            defaultCapacity: prewarmCount
        );

        // 预生成对象并立即放回池中（预热）
        var prewarmNetworkObjects = new List<NetworkObject>();
        for (var i = 0; i < prewarmCount; i++)
        {
            prewarmNetworkObjects.Add(m_PooledObjects[prefab].Get());
        }
        foreach (var networkObject in prewarmNetworkObjects)
        {
            m_PooledObjects[prefab].Release(networkObject);
        }

        // 注册自定义生成处理器到Netcode
        NetworkManager.Singleton.PrefabHandler.AddHandler(
            prefab, 
            new PooledPrefabInstanceHandler(prefab, this)
        );
    }
}

/// <summary>
/// 序列化结构体：配置池化预制体及其预热数量
/// </summary>
[Serializable]
internal struct PoolConfigObject
{
    public GameObject Prefab;   // 要池化的预制体
    public int PrewarmCount;    // 初始预生成数量
}

/// <summary>
/// 自定义网络对象处理器：覆盖Netcode的默认生成/销毁逻辑
/// </summary>
internal class PooledPrefabInstanceHandler : INetworkPrefabInstanceHandler
{
    private GameObject m_Prefab;  // 关联的预制体
    private NetworkObjectPool m_Pool; // 所属对象池

    public PooledPrefabInstanceHandler(GameObject prefab, NetworkObjectPool pool)
    {
        m_Prefab = prefab;
        m_Pool = pool;
    }

    /// <summary>
    /// 当Netcode需要生成对象时，从池中获取
    /// </summary>
    NetworkObject INetworkPrefabInstanceHandler.Instantiate(ulong ownerClientId, Vector3 position, Quaternion rotation)
    {
        return m_Pool.GetNetworkObject(m_Prefab, position, rotation);
    }

    /// <summary>
    /// 当Netcode需要销毁对象时，将对象返回池中
    /// </summary>
    void INetworkPrefabInstanceHandler.Destroy(NetworkObject networkObject)
    {
        m_Pool.ReturnNetworkObject(networkObject, m_Prefab);
    }
}